#region using directives

using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Navigation;
using System.Windows.Threading;
using Assergs.Windows.Controls;
using Bookvar.AddIn;
using Bookvar.ApplicationModel;
using Bookvar.Collaboration;
using Bookvar.Common;
using Bookvar.ObjectModel;
using Bookvar.ObjectModel.Collections;
using Bookvar.ServiceModel;
using Bookvar.ServiceModel.Actions;
using Bookvar.UI;
using Bookvar.UI.Adorners;
using Bookvar.UI.Arrangers;
using Bookvar.UI.Commands;
using Bookvar.UI.ViewModel;
using BookvarWpf.Windows;
using LocalizationResources = Bookvar.UI.Localization.Resources;
using BookvarWpf.Windows.Collaboration;
using Microsoft.Samples.KMoore.WPFSamples.Transition;
using Assergs.Windows;
using System.Threading;
using MessageBox = System.Windows.MessageBox;

#endregion

namespace BookvarWpf
{
    /// <summary>
    /// Interaction logic for MainPage.xaml
    /// </summary>
    public partial class MainPage : IMainPage
    {
        private delegate void LoadAddInsDelegate();

        private CollaborationChat chatWindow;
        private CollaborationUsersList usersWindow;
        private StartServerWindow startServerWindow;
        private AddAttachmentsWindow addAttachmentsWindow;
        private MindMap currentMap;
        private string currentMapImage;
        private bool isTransitionedFirstTime = true;
        private bool dragging;
        private readonly bool shouldLoadMap;
        private readonly DispatcherTimer timer;
        private Thread workerThread;

        private readonly MindmapCollection loadedMaps = new MindmapCollection();
        private readonly IMainPagePresenter presenter;
        private PleaseWait pwDlg;

        public static readonly DependencyProperty IsTransitioningProperty =
            DependencyProperty.Register( "IsTransitioning", typeof ( bool ), typeof ( MainPage ),
                                         new FrameworkPropertyMetadata( default( bool ), OnIsTransitioningChanged ) );

        public bool IsTransitioning
        {
            get { return (bool) GetValue( IsTransitioningProperty ); }
            set { SetValue( IsTransitioningProperty, value ); }
        }

        public MindmapCollection LoadedMaps
        {
            get
            {
                return loadedMaps;
            }
        }

        public void FocusMindmap(MindMap mindmap)
        {
            tabs.SelectedIndex = loadedMaps.IndexOf( mindmap );
        }

        public static FileSystemPersistenceService PersistenceService
        {
            get
            {
                return
                    BookvarApplication.Current.ServiceLayer.GetService<IPersistenceService>() as
                    FileSystemPersistenceService;
            }
        }

        private static IAutoSaveRecoveryService AutoSaveRecoveryService
        {
            get
            {
                return
                    BookvarApplication.Current.ServiceLayer.GetService<IAutoSaveRecoveryService>();
                    //as FileSystemAutoSaveRecoveryService;
            }
        }

        private static IViewService ViewService
        {
            get { return BookvarApplication.Current.ServiceLayer.GetService<IViewService>(); }
        }

        private static IAddinService addinService
        {
            get { return BookvarApplication.Current.ServiceLayer.GetService<IAddinService>(); }
        }

        private static IMindmapService mindmapService
        {
            get { return BookvarApplication.Current.ServiceLayer.GetService<IMindmapService>(); }
        }

        public MainPage()
        {
            InitializeComponent();
            var collaborationManager = new CollaborationManager();

            var viewModel = new MainPageViewModel();
            ViewModelBase.AddCommandAndInputBindings( this, viewModel );

            BookvarApplication.Current.ServiceLayer.AddService<IAddinService>( new AddInService() );
            BookvarApplication.Current.ServiceLayer.AddService<IAdornerService>( new AdornerService( mindMapPanel ) );
            BookvarApplication.Current.ServiceLayer.AddService<IPersistenceService>( new FileSystemPersistenceService() );
            BookvarApplication.Current.ServiceLayer.AddService<ICollaborationManager>( collaborationManager );
            BookvarApplication.Current.ServiceLayer.AddService<ICollaborationEventsPublisher>( collaborationManager );
            BookvarApplication.Current.ServiceLayer.AddService<IViewService>( new ViewService( mindMapPanel, zoomer,
                                                                                               scrollViewer ) );
            BookvarApplication.Current.ServiceLayer.AddService<IMindmapService>( new MindMapService( mindMapPanel, this) );
            BookvarApplication.Current.ServiceLayer.AddService<IErrorService>( new ErrorService() );
            
            ViewService.InitializeDragBehavior();

            PersistenceService.Saving += PersistenceService_Saving;
            ToolWindow.ModalContainerPanel = root;
            Loaded += MainPage_Loaded;
            tabs.ItemsSource = loadedMaps;
            combo.SelectionChanged += ComboSelectionChanged;
            mindMapPanel.SelectedTopicChanged += OnSelectedTopicChanged;
            startDatePicker.ValueChanged += OnStartDatePickerValueChanged;
            endDatePicker.ValueChanged += OnEndDatePickerValueChanged;
            cmbSkins.SelectionChanged += SkinSelectionChanged;

            var binding = new Binding( "IsTransitioning" ) { Source = rotationPresenter };
            SetBinding( IsTransitioningProperty, binding );

            AddHandler( CloseableTabItem.CloseTabEvent, new RoutedEventHandler( CloseTab ) );
            tabs.SelectionChanged += tabs_SelectionChanged;

            scrollViewer.ScrollToHorizontalOffset( 400 );
            scrollViewer.ScrollToVerticalOffset( 700 );
            Logger.LogProvider = new WindowLogProvider( content.WindowsContainer );

            AddKeyBindings();

            AddCommandBindings();
            loadedMaps.CollectionChanged += loadedMaps_CollectionChanged;

            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds( 2 );
            timer.Tick += timer_Tick;
            timer.Start();
            currentMap = mindMapPanel.Mindmap;

            loadedMaps.Add( currentMap );

            BookvarApplication.Current.Navigating += OnNavigating;

            presenter = new MainPagePresenter( this );
            AutoSaveRecoveryService.AutoSaving += AutoRecoveryService_AutoSaving;
            PersistenceService.RegisterMindmapForPersistence( currentMap );
            mindMapPanel.PreviewMouseLeftButtonDown += delegate { dragging = true; };
            mindMapPanel.PreviewMouseLeftButtonUp += delegate { dragging = false; };
            mindMapPanel.PreviewDrop += delegate { dragging = false; };
            BookvarApplication.Current.MainWindow.Closing += MainWindow_Closing;
        }

        public MainPage( IEnumerable<string> fileNames ) : this()
        {
            loadedMaps.Clear();

            foreach ( var fileName in fileNames.Where( s => !string.IsNullOrEmpty( s ) ) )
            {
                mindmapService.OpenMindmapFromDisk( fileName );
            }

            //add default map if the passed collection was empty
            if ( loadedMaps.Count == 0 )
            {
                loadedMaps.Add( mindMapPanel.Mindmap );
            }

            currentMap = loadedMaps.Last();

            mindMapPanel.Mindmap = null;
            shouldLoadMap = true;

            UpdateTitle();
        }

        private void PersistenceService_Saving( object sender, SavingEventArgs e )
        {
            if ( e.Map.Key == currentMap.Key )
            {
                //currentMap.Properties.Layout = combo.SelectedItem.ToString();
                //currentMap.Properties.Skin = cmbSkins.SelectedItem.ToString();
            }
        }

        private void MainWindow_Closing( object sender, System.ComponentModel.CancelEventArgs e )
        {
            // TODO: Add checking for unsaved maps to ensure that no data has been lost

            foreach ( MindMap map in loadedMaps )
            {
                AutoSaveRecoveryService.RemoveMapForAutoSave( map );
            }
        }

        private void AutoRecoveryService_AutoSaving( object sender, AutoSavingEventArgs e )
        {
            if ( e.Map.Key == currentMap.Key )
            {
                //currentMap.Properties.Layout = combo.SelectedItem.ToString();
                //currentMap.Properties.Skin = cmbSkins.SelectedItem.ToString();
            }
        }

        private static void loadedMaps_CollectionChanged( object sender, NotifyCollectionChangedEventArgs e )
        {
            if ( e.NewItems != null && e.NewItems.Count > 0 )
            {
                AutoSaveRecoveryService.AddMapForAutoSave( e.NewItems[ 0 ] as MindMap );
                BookvarApplication.Current.ServiceLayer.AddService<IActionService>( new ActionService(), ((MindMap)e.NewItems[ 0 ]).Key.ToString() );
            }
            else if ( e.OldItems != null && e.OldItems.Count > 0 )
            {
                AutoSaveRecoveryService.RemoveMapForAutoSave( e.OldItems[ 0 ] as MindMap );
                BookvarApplication.Current.ServiceLayer.RemoveService<IActionService>(
                    ( (MindMap) e.OldItems[0] ).Key.ToString() );
            }
        }

        private void MainPage_Loaded( object sender, RoutedEventArgs e )
        {
            IViewService viewService = BookvarApplication.Current.ServiceLayer.GetService<IViewService>();
            IAdornerService adornerService = BookvarApplication.Current.ServiceLayer.GetService<IAdornerService>();

            if ( viewService == null )
            {
                BookvarApplication.Current.ServiceLayer.AddService<IViewService>(
                    new ViewService( mindMapPanel, zoomer, scrollViewer ) );
            }
            if ( adornerService == null )
            {
                BookvarApplication.Current.ServiceLayer.AddService<IAdornerService>( new AdornerService( mindMapPanel ) );
            }
            if ( shouldLoadMap )
            {
                mindMapPanel.Mindmap = currentMap;
            }

            workerThread = new Thread( delegate()
                                           {
                                               addinService.RebuildAddinStore();
                                               Dispatcher.BeginInvoke( DispatcherPriority.Background,
                                                                       new LoadAddInsDelegate( LoadAddIns ) );
                                           } );
            workerThread.Start();


            Application.Current.MainWindow.WindowStyle = WindowStyle.SingleBorderWindow;
        }

        private void timer_Tick( object sender, EventArgs e )
        {
            RethumbMindmap();
        }

        private void tabs_SelectionChanged( object sender, SelectionChangedEventArgs e )
        {
            if ( !tabs.IsLoaded )
            {
                return;
            }
            if ( tabs.Items.Count > 0 && tabs.SelectedIndex >= 0 )
            {
                GoToMap( tabs.SelectedIndex );
            }
        }

        private void CloseTab( object source, RoutedEventArgs args )
        {
            TabItem tabItem = args.OriginalSource as TabItem;
            if ( tabItem != null )
            {
                TabControl tabControl = args.Source as TabControl;
                if ( tabControl != null && loadedMaps.Count > 1 )
                {
                    int index = tabControl.ItemContainerGenerator.IndexFromContainer( tabItem );
                    loadedMaps.RemoveAt( index );
                }
                //tabControl.Items.Remove(tabItem);
            }
        }

        private void AddKeyBindings()
        {
            KeyBinding switchMapsBinding =
                new KeyBinding( BookvarCommands.SwitchMaps, new KeyGesture( Key.Tab, ModifierKeys.Control ) );
            switchMapsBinding.CommandTarget = this;
            InputBindings.Add( switchMapsBinding );

            KeyBinding createNewMapBinding =
                new KeyBinding( BookvarCommands.CreateNewMap, new KeyGesture( Key.N, ModifierKeys.Control ) );

            createNewMapBinding.CommandTarget = this;
            InputBindings.Add( createNewMapBinding );

            KeyBinding openMapBinding =
                new KeyBinding( BookvarCommands.OpenMap, new KeyGesture( Key.O, ModifierKeys.Control ) );

            openMapBinding.CommandTarget = this;
            InputBindings.Add( openMapBinding );

            KeyBinding saveBinding =
                new KeyBinding( BookvarCommands.SaveMap, new KeyGesture( Key.S, ModifierKeys.Control ) );

            saveBinding.CommandTarget = this;
            InputBindings.Add( saveBinding );

            KeyBinding notesBinding =
                new KeyBinding( BookvarUICommands.ShowNotes, new KeyGesture( Key.N, ModifierKeys.Alt ) );

            notesBinding.CommandTarget = this;
            InputBindings.Add( notesBinding );

            KeyBinding hyperlinkBinding =
                new KeyBinding( BookvarUICommands.ShowHyperlink, new KeyGesture( Key.K, ModifierKeys.Control ) );

            hyperlinkBinding.CommandTarget = this;
            InputBindings.Add( hyperlinkBinding );
        }

        private void AddCommandBindings()
        {
            var createNewMapCommandBinding =
                new CommandBinding( BookvarCommands.CreateNewMap, CreateNewMapCommandExecuted );
            CommandBindings.Add( createNewMapCommandBinding );

            var openMapCommandBinding = new CommandBinding( BookvarCommands.OpenMap, OpenMapCommandExecuted );
            CommandBindings.Add( openMapCommandBinding );

            var saveMapCommandBinding = new CommandBinding( BookvarCommands.SaveMap, SaveMapCommandExecuted );
            CommandBindings.Add( saveMapCommandBinding );

            var saveAsMapCommandBinding = new CommandBinding( ApplicationCommands.SaveAs, SaveAsMapCommandExecuted );
            CommandBindings.Add( saveAsMapCommandBinding );

            var switchMapsCommandBinding = new CommandBinding( BookvarCommands.SwitchMaps, SwitchMapsCommandExecuted );
            CommandBindings.Add( switchMapsCommandBinding );

            var showAttachmentsCommandBinding =
                new CommandBinding( BookvarUICommands.ShowAttachments, ShowAttachmentsCommandExecuted );
            CommandBindings.Add( showAttachmentsCommandBinding );

            var showNotesCommandBinding = new CommandBinding( BookvarUICommands.ShowNotes, ShowNotesCommandExecuted );
            CommandBindings.Add( showNotesCommandBinding );

            var showHyperlinkCommandBinding =
                new CommandBinding( BookvarUICommands.ShowHyperlink, ShowHyperlinkCommandExecuted );
            CommandBindings.Add( showHyperlinkCommandBinding );
        }

        private void OnNavigating( object sender, NavigatingCancelEventArgs e )
        {
            if ( IsLoaded )
            {
                BookvarApplication.Current.ServiceLayer.RemoveService( typeof ( IAdornerService ) );
                //BookvarApplication.Current.ServiceLayer.RemoveService(typeof(IPersistenceService));
                BookvarApplication.Current.ServiceLayer.RemoveService( typeof ( IViewService ) );
                //BookvarApplication.Current.ServiceLayer.RemoveService(typeof(ICollaborationManager));
                //BookvarApplication.Current.ServiceLayer.RemoveService(typeof(ICollaborationEventsPublisher));
                timer.Stop();

                BookvarApplication.Current.Navigating -= OnNavigating;
            }
        }

        protected override void OnKeyUp( KeyEventArgs e )
        {
            if ( e.Key == Key.LeftCtrl )
            {
                SwitchMaps window = FindSwitchMapsWindow();
                if ( window != null )
                {
                    int mapIndex = window.lstMaps.SelectedIndex;
                    window.Close();
                    tabs.SelectedIndex = mapIndex;
                    //GoToMap(mapIndex);
                    e.Handled = true;
                }
                else
                {
                    e.Handled = false;
                }
            }

            base.OnKeyUp( e );
        }

        private static void SwitchMapsCommandExecuted( object sender, ExecutedRoutedEventArgs e )
        {
            MainPage page = (MainPage) sender;
            SwitchMaps window = page.FindSwitchMapsWindow();
            if ( window == null )
            {
                window = new SwitchMaps( page.loadedMaps );
                window.SetCurrentMap( page.currentMap );
                window.Margin = new Thickness( 150, 20, 0, 0 );
                window.Parent = page.content.WindowsContainer;
                window.Show();
            }

            window.MoveToNextMap();
        }

        private SwitchMaps FindSwitchMapsWindow()
        {
            foreach ( UIElement element in content.WindowsContainer.Children )
            {
                SwitchMaps window = element as SwitchMaps;
                if ( window != null )
                {
                    return window;
                }
            }
            return null;
        }

        private void AddMindMap( MindMap map )
        {
            //RethumbMindmap();
            PersistenceService.RegisterMindmapForPersistence( map );

            if ( loadedMaps.Contains( map.Key ) )
            {
                loadedMaps.Remove( map.Key );
            }

            loadedMaps.Add( map );

            tabs.SelectedIndex = loadedMaps.Count - 1;
            UpdateTitle();
        }

        private void GoToMap( int mapIndex )
        {
            currentMap = loadedMaps[ mapIndex ];
            //this.LayoutUpdated += new EventHandler(MainPage_LayoutUpdated);
            Random random = new Random();
            RotateDirection direction = (RotateDirection) random.Next( 4 );

            //this.GetL
            RotateTransition transition = FindResource( "rotateTransition" ) as RotateTransition;
            if ( transition != null )
            {
                transition.Direction = direction;
            }
            //rotateTransition.

            if ( rotationPresenter.Content == null )
            {
                currentMapImage = MapThumbnailUtility.GenerateMapImage( scrollViewer, currentMapImage );
                rotationPresenter.Visibility = Visibility.Hidden;
                rotationPresenter.Content = new Picture( currentMapImage );
            }
            else
            {
                mindMapPanel.Mindmap = currentMap;
                mindMapPanel.UpdateLayout();
                currentMapImage = MapThumbnailUtility.GenerateMapImage( scrollViewer, currentMapImage );
                rotationPresenter.Content = new Picture( currentMapImage );
            }
        }

        private void OnSelectedTopicChanged( object sender, SelectedTopicChangedEventArgs e )
        {
            CustomProperty timelineProperty;
            if (
                e.NewSelectedTopic.CustomProperties.TryGetItem( TimelineTopicArranger.TimelineStartDateKey,
                                                                out timelineProperty ) )
            {
                startDatePicker.Value = (DateTime) timelineProperty.Value;
            }
            else
            {
                startDatePicker.Value = null;
            }
            if (
                e.NewSelectedTopic.CustomProperties.TryGetItem( TimelineTopicArranger.TimelineEndDateKey,
                                                                out timelineProperty ) )
            {
                endDatePicker.Value = (DateTime) timelineProperty.Value;
            }
            else
            {
                endDatePicker.Value = null;
            }
        }

        private void RethumbMindmap()
        {
            if ( mindMapPanel != null &&
                 mindMapPanel.MainTopic != null &&
                 IsTransitioning == false &&
                 dragging == false )
            {
                if ( ViewService != null && !ViewService.IsDragging )
                {
                    double horizontalOffset = scrollViewer.HorizontalOffset;
                    double verticalOffset = scrollViewer.VerticalOffset;
                    //string oldValue = mindMapPanel.MainTopic.Thumbnail;
                    scrollViewer.ScrollToHorizontalOffset( 0 );
                    scrollViewer.ScrollToVerticalOffset( 0 );
                    scrollViewer.UpdateLayout();
                    string result = MapThumbnailUtility.GenerateMapThumbnail( mindMapPanel,
                                                                              scrollViewer.HorizontalOffset,
                                                                              scrollViewer.VerticalOffset,
                                                                              mindMapPanel.MainTopic.Thumbnail );
                    scrollViewer.ScrollToHorizontalOffset( horizontalOffset );
                    scrollViewer.ScrollToVerticalOffset( verticalOffset );
                    if ( result != null )
                    {
                        mindMapPanel.MainTopic.Thumbnail = result;
                    }
                }
            }
        }

        private void LoadAddIns()
        {
            foreach ( BookvarHostView hostView in addinService.LoadAddins<BookvarHostView>() )
            {
                CreateAndInsertAddInButton( hostView );
            }

            foreach ( EditableBookvarHostView hostView in addinService.LoadAddins<EditableBookvarHostView>() )
            {
                CreateAndInsertAddInButton( hostView );
            }
        }

        private void CreateAndInsertAddInButton( IBookvarAddin bookvarAddin )
        {
            AddinInfo addinInfo = bookvarAddin.GetInfo();
            ImageButton button = new ImageButton();
            button.Content = addinInfo.Name;
            button.ToolTip = addinInfo.Description;
            button.Orientation = Orientation.Vertical;
            button.IsToolStyle = true;
            button.ImageSource = (ImageSource) new ImageSourceConverter().ConvertFrom( addinInfo.Image );
            button.Tag = bookvarAddin;
            button.Click += ExecuteAddIn;
            StackPanel addInStackPanel = GetAddInStackPanel( addinInfo.Group );
            addInStackPanel.Children.Add( button );
        }

        private StackPanel GetAddInStackPanel( string groupName )
        {
            //If groupName exists already, return it's StackPanel
            for ( int i = 0; i < addinsStackPanel.Children.Count; i++ )
            {
                RibbonPanel ribbonPanel = (RibbonPanel) addinsStackPanel.Children[ i ];

                if ( ribbonPanel.Header.ToString() == groupName )
                {
                    return (StackPanel) ribbonPanel.Content;
                }
            }

            //Create new ribbon panel for the new addin group and return it's StackPanel
            StackPanel newStackPanel = new StackPanel();
            newStackPanel.Orientation = Orientation.Horizontal;

            RibbonPanel newRibbonPanel = new RibbonPanel();
            newRibbonPanel.Header = groupName;
            newRibbonPanel.Content = newStackPanel;
            addinsStackPanel.Children.Add( newRibbonPanel );

            return newStackPanel;
        }

        //private static Collection<AddInToken> LoadAddinTokens()
        //{
        //    String addInRoot = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);


        //    AddInStore.Rebuild(addInRoot);
        //    Collection<AddInToken> tokens = AddInStore.FindAddIns(
        //        typeof(BookvarHostView), addInRoot);

        //    return tokens;
        //}

        private void ExecuteAddIn( object sender, RoutedEventArgs e )
        {
            ImageButton button = sender as ImageButton;
            if ( button == null )
            {
                throw new ArgumentException( "Parameter sender should be ImageButton" );
            }

            BookvarHostView bookvarAddIn = button.Tag as BookvarHostView;
            if ( bookvarAddIn != null )
            {
                bookvarAddIn.Execute( mindMapPanel.MainTopic );
            }

            EditableBookvarHostView editableBookvarAddIn = button.Tag as EditableBookvarHostView;
            if ( editableBookvarAddIn != null )
            {
                Topic resultTopic = editableBookvarAddIn.Execute( mindMapPanel.MainTopic );
                if ( resultTopic != null )
                {
                    MindMap newMap = new MindMap( new MainTopic( resultTopic ) );
                    RegisterMapResources( newMap );
                    AddMindMap( newMap );
                    currentMap = newMap;

                    // HACK:
                    foreach ( Topic topic in newMap.GetAllTopics() )
                    {
                        foreach ( Resource resource in topic.Resources )
                        {
                            string tempFile = Path.GetTempFileName();
                            File.WriteAllBytes( tempFile, (byte[]) resource.ResourceBytes );

                            var saveFileResourceAction =
                                new SaveFileResourceAction( PersistenceService, newMap, resource, tempFile );

                            saveFileResourceAction.Execute();
                        }
                    }

                    mindMapPanel.InvalidateTopicsArrange();
                }
            }
        }

        private static void RegisterMapResources( MindMap newMap )
        {
            PersistenceService.RegisterMindmapForPersistence( newMap );
            RegisterMapResourceRecursive( newMap, newMap.MainTopic );
        }

        //TODO: this should be done in the persister (using actions)
        private static void RegisterMapResourceRecursive( MindMap newMap, Topic topic )
        {
            foreach ( Resource resource in topic.Resources )
            {
                if ( resource.ItemSource is byte[] )
                {
                    PersistenceService.SaveFileResourceToPersistence(
                        newMap.Key, resource, new MemoryStream( (byte[]) resource.ItemSource ) );
                }
            }
            foreach ( Topic subTopic in topic.SubTopics )
            {
                RegisterMapResourceRecursive( newMap, subTopic );
            }
        }

        //TODO: use dependency property for current map and property changed callback for updating the title
        private void UpdateTitle()
        {
            if ( !string.IsNullOrEmpty( currentMap.FileName ) )
            {
                string fileName = Path.GetFileNameWithoutExtension( currentMap.FileName );
                WindowTitle = string.Format( CultureInfo.CurrentCulture, LocalizationResources.BookvarTitleOpenedFile,
                                             fileName );
            }
            else
            {
                WindowTitle = LocalizationResources.BookvarTitleNewMindMap;
            }
        }

        private void ConnectToServerConnectEvent( object sender, ConnectClickedEventArgs e )
        {
            ( (ToolWindow) sender ).Close();

            btnStartServer.Visibility = Visibility.Collapsed;
            btnStopServer.Visibility = Visibility.Collapsed;

            presenter.BeginConnectToServer( e.Host, e.Name, OnEndJoin );

            pwDlg = new PleaseWait();
            pwDlg.Margin = new Thickness( 50, 20, 0, 0 );
            pwDlg.ShowDialog();
        }

        private static void OnIsTransitioningChanged( object sender, DependencyPropertyChangedEventArgs args )
        {
            MainPage page = (MainPage)sender;
            if ( page.rotationPresenter.IsTransitioning )
            {
                if ( !page.isTransitionedFirstTime )
                {
                    page.rotationPresenter.Visibility = Visibility.Visible;
                    page.scrollViewer.Visibility = Visibility.Hidden;
                }
            }
            else
            {
                //page.rotationPresenter.InvalidateProperty(TransitionPresenter.TransitionProperty);
                if ( page.isTransitionedFirstTime )
                {
                    page.mindMapPanel.Mindmap = page.currentMap;
                    page.mindMapPanel.UpdateLayout();
                    page.currentMapImage =
                        MapThumbnailUtility.GenerateMapImage( page.scrollViewer, page.currentMapImage );
                    page.rotationPresenter.Visibility = Visibility.Visible;
                    page.scrollViewer.Visibility = Visibility.Hidden;

                    page.isTransitionedFirstTime = false;

                    page.rotationPresenter.Content = new Picture( page.currentMapImage );
                    //page.transitioned = true;
                }
                else
                {
                    page.scrollViewer.Visibility = Visibility.Visible;
                    page.rotationPresenter.Visibility = Visibility.Hidden;
                    //page.transitioned = false;
                    //page.LayoutUpdated -= MainPage_LayoutUpdated;
                }
                page.mindMapPanel.MainTopicPresenter.Focus();
            }
        }

        #region Collaboration

        private void OnEndJoin( IAsyncResult iar )
        {
            if ( Dispatcher.CheckAccess() )
            {
                try
                {
                    CollaborationUser[] users = presenter.EndConnectToServer( iar );
                    HandleEndJoin( users );
                    btnConnectToServer.Visibility = Visibility.Collapsed;
                    btnDisconnectFromServer.Visibility = Visibility.Visible;
                }
                catch ( CollaborationException ex )
                {
                    Logger.Log( ex.ToString() );
                    HandleEndJoinError();
                }
            }
            else
            {
                Dispatcher.BeginInvoke( DispatcherPriority.Normal, new Action<IAsyncResult>( OnEndJoin ), iar );
            }
        }

        private void HandleEndJoinError()
        {
            string errorMsg = LocalizationResources.ErrorCouldNotConnectToServer;
            pwDlg.ShowError( errorMsg );
            ExitCollaborationSession();
        }

        private void HandleEndJoin( IEnumerable<CollaborationUser> users )
        {
            if ( users == null )
            {
                // TODO: Check this condition. This seems deprecated.
                pwDlg.ShowError( "Error: Username already exist!" );
                ExitCollaborationSession();
            }
            else
            {
                try
                {
                    pwDlg.Close();

                    string toLog = string.Empty;
                    foreach ( CollaborationUser user in users )
                    {
                        toLog += user.ToString();
                    }

                    Logger.Log( toLog );

                    MindMap map = presenter.GetMindmapFromServer();
                    ShowCollaborationWindows();
                    AddMindMap( map );
                }
                catch ( Exception ex )
                {
                    Logger.Log( ex.ToString() );
                    throw;
                }
            }
        }

        private void ExitCollaborationSession()
        {
            try
            {
                presenter.StopCollaborationClient();
            }
            catch ( CollaborationException ex )
            {
                Logger.Log( ex.ToString() );
            }
        }

        public void CollaborationStopped()
        {
            // show a message that the collaboration has stopped.
            HideCollaborationWindows();

            btnConnectToServer.Visibility = Visibility.Visible;
            btnDisconnectFromServer.Visibility = Visibility.Collapsed;
            btnStartServer.Visibility = Visibility.Visible;
            btnStopServer.Visibility = Visibility.Collapsed;
        }

        public void CollaborationServerStarted()
        {
            ShowCollaborationWindows();

            if ( startServerWindow != null )
            {
                startServerWindow.Close();
            }

            btnConnectToServer.Visibility = Visibility.Collapsed;
            btnDisconnectFromServer.Visibility = Visibility.Collapsed;
            btnStartServer.Visibility = Visibility.Collapsed;
            btnStopServer.Visibility = Visibility.Visible;
        }

        public void ShowConnectionToServerLostMessage()
        {
            MessageBox.Show( LocalizationResources.ErrorConnectionToServerLost );
        }

        public void ShowServerStoppedMessage()
        {
            MessageBox.Show( LocalizationResources.ErrorServerStopped );
        }

        public void StartCollaborationServer()
        {
            startServerWindow = new StartServerWindow( mindMapPanel.Mindmap );
            ShowModalDialog( startServerWindow );
        }

        private void ShowCollaborationWindows()
        {
            usersWindow = new CollaborationUsersList();
            usersWindow.VerticalAlignment = VerticalAlignment.Top;
            usersWindow.HorizontalAlignment = HorizontalAlignment.Left;
            usersWindow.Margin = new Thickness( 33 );
            usersWindow.StartPosition = ToolWindowStartPosition.Manual;
            ShowDialog( usersWindow );

            chatWindow = new CollaborationChat();
            chatWindow.VerticalAlignment = VerticalAlignment.Top;
            chatWindow.HorizontalAlignment = HorizontalAlignment.Left;
            chatWindow.Margin = new Thickness( 33, 333, 0, 0 );
            chatWindow.StartPosition = ToolWindowStartPosition.Manual;
            ShowDialog( chatWindow );
        }

        private void HideCollaborationWindows()
        {
            if ( chatWindow != null )
            {
                chatWindow.Close();
            }

            if ( usersWindow != null )
            {
                usersWindow.Close();
            }
        }

        #endregion
    }

    internal class Picture
    {
        private readonly string uri;

        public Picture( string uri )
        {
            this.uri = uri;
        }

        [SuppressMessage( "Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode",
            Justification = "Used in xaml data binding" )]
        public string Uri
        {
            get { return uri; }
        }
    }
}
